﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Mesuro.Equation {
	internal class EqProtoOperator : EqTerm {

		private int selected = 4;
		private EqOperatorDefinition[] definitions = { null, null, null, null };

		public EqOperatorDefinition Definition {
			get { return definitions[selected]; }
		}

		public EqOperatorArguments Arguments {
			get { return Definition.Arguments; }
		}

		public int Precedence {
			get { return (((~(int)Arguments) & 0x3) << 4) | Definition.Precedence; }
		}

		internal EqProtoOperator( String key )
			: base() {
			LinkedList<EqOperatorDefinition> list = EqOperatorDefinition.FindOperators( key );

			if (list.Count == 0)
				throw new MalformedExpressionException( String.Format( "No operators defined for '{0}'.", key ) );

			foreach (EqOperatorDefinition def in list)
				definitions[(int)def.Arguments] = def;

			selected = 3;

			while (Definition == null)
				selected--;
		}

		public bool Select( EqOperatorArguments args ) {
			//If there is no definition that accepts args, return
			if (definitions[(int)args] == null) return false;

			//Otherwise, select the corresponding definition and return
			selected = (int)args;
			return true;
		}
		public bool SelectNext() {
			//If we're already on last definition, can't select next
			if (selected == 0) return false;

			//Use local variable so we don't change the state of this object unless it's safe
			int sel = selected;

			//Find next definition
			do
				sel--;
			while (definitions[sel] == null && sel > 0);

			//No next definition
			if (Definition == null) return false;

			//Change state now that we know this state is valid
			selected = sel;
			return true;
		}
		public bool HasDefinition( EqOperatorArguments args ) {
			return definitions[(int)args] != null;
		}

		public override EqTerm Evaluate( EqScope scope ) {
			throw new InvalidOperationException( "Cannot evaluate a proto operator" );
		}

		public override int ComplexityCost() {
			return 1;
		}

		public override string ToString() {
			return '/' + Definition.Key + '/';
		}

	}
}